/*
 * Tree.java  0.4.0 / Oct 27, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing;

import com.cute4j.swing.events.TreeModelEvent;
import com.cute4j.swing.events.TreeModelListener;
import com.cute4j.swing.events.TreeSelectionEvent;
import com.cute4j.swing.events.TreeSelectionListener;
import com.cute4j.swing.tree.DefaultMutableTreeNode;
import com.cute4j.swing.tree.TreeModel;
import com.cute4j.swing.tree.TreeNode;
import com.cute4j.swing.tree.TreePath;

/**
 * Tree Component.
 *
 * @cute4j.native
 *    generate="header"
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class Tree extends Component {

// Static Initialization. ------------------------------------------------------

  static {
    _initialize(TreeNode.class);
  }

// Private Fields. -------------------------------------------------------------

  private SwingIconSet iconSet;
  private TreeModel model;
  private ModelListener modelListener;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new Tree object.
   */
  public Tree() {
    this(null);
  }

  /**
   * Constructs new Tree object.
   *
   * @param model the tree model
   */
  public Tree(TreeModel model) {
    iconSet = new SwingIconSet(this);
    modelListener = new ModelListener(this);
    _createIcon(_delegate, iconSet); // NOPMD
    this.model = model;
    if (model != null) {
      _setUseModel(_delegate, true); // NOPMD
      model.addTreeModelListener(modelListener);
    }
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Returns tree model.
   *
   * @return tree model
   */
  public TreeModel getModel() {
    return model;
  }

  /**
   * Sets tree model.
   *
   * @param model the tree model
   */
  public void setModel(TreeModel model) {
    // TODO: temp - implement
    final TreeModel oldModel = this.model;
    if (oldModel != model) { // NOPMD
      disposedCheck();
      if (oldModel != null) {
        oldModel.removeTreeModelListener(modelListener);
      }
      this.model = model;
      if (model == null) {
        _setUseModel(_delegate, false);
      } else {
        _setUseModel(_delegate, true);
        model.addTreeModelListener(modelListener);
      }
      //firePropertyChange(PROPERTY_MODEL, oldModel, model);
    }
  }

  /**
   * Adds tree selection listener.
   *
   * @param listener the tree selection listener
   */
  public void addChangeListener(TreeSelectionListener listener) {
    listenerList.add(TreeSelectionListener.class, listener);
  }

  /**
   * Removes tree selection listener.
   *
   * @param listener the tree selection listener
   */
  public void removeChangeListener(TreeSelectionListener listener) {
    listenerList.remove(TreeSelectionListener.class, listener);
  }

  /**
   * Returns tree selection listeners.
   *
   * @return tree selection listeners
   */
  public TreeSelectionListener[] getChangeListeners() {
    int count = listenerList.getListenerCount(TreeSelectionListener.class);
    TreeSelectionListener[] listeners = new TreeSelectionListener[count];
    if (count > 0) {
      System.arraycopy(
                listenerList.getListenersArray(TreeSelectionListener.class), 0,
                listeners,  0, count);
    }
    return listeners;
  }

// Protected Methods. ----------------------------------------------------------

  /**
   * Fires value changed event.
   *
   * @param event the selection event
   */
  protected void fireValueChanged(TreeSelectionEvent event) {
    int count = listenerList.getListenerCount(TreeSelectionListener.class);
    if (count > 0) {
      TreeSelectionListener[] listeners =
          (TreeSelectionListener[])listenerList.
                                 getListenersArray(TreeSelectionListener.class);
      for (int i = count; --i >= 0;) {
        listeners[i].valueChanged(event);
      }
    }
  }

// Overridden Methods. ---------------------------------------------------------

  void componentDestroyed() {
    super.componentDestroyed();
    if (model != null) {
      model.removeTreeModelListener(modelListener);
    }
  }

// Native Callbacks. -----------------------------------------------------------

  TreeNode _getRootNode() {
    if (model != null) {
      Object root = model.getRoot();
      if (root instanceof TreeNode) {
        return (TreeNode)root;
      }
    }
    return null;
  }

  boolean _setNodeIcon(TreeNode node) {
    if (node instanceof DefaultMutableTreeNode) {
      Icon icon = ((DefaultMutableTreeNode)node).getIcon();
      if (icon != null) {
        iconSet.setIcon(icon, null);
        return true;
      }
    }
    iconSet.setIcon(null, null);
    return false;
  }

  void _nodeSelected(TreeNode node) {
    TreePath path = new TreePath(node); // TODO: make full path to the root
    fireValueChanged(new TreeSelectionEvent(node, path, true, null, null));
  }

// Package-Private Native Methods.----------------------------------------------

  native long _create();

  native void _createIcon(long delegate, SwingIconSet iconSet);

  native void _setUseModel(long delegate, boolean useModel);

// Private Static Native Methods. ----------------------------------------------

  private static native void _initialize(Class treeNodeClass);

// Inner Classes. --------------------------------------------------------------

  /**
   * Tree Model Listener.
   */
  static class ModelListener implements TreeModelListener {
    final Tree tree;
    public ModelListener(Tree tree) {
      this.tree = tree;
    }
    public void treeNodesChanged(TreeModelEvent event) {
      // TODO: implement
    }
    public void treeNodesInserted(TreeModelEvent event) {
      // TODO: implement
    }
    public void treeNodesRemoved(TreeModelEvent event) {
      // TODO: implement
    }
    public void treeStructureChanged(TreeModelEvent event) {
      // TODO: implement
    }
  }

}
